# -*- coding: utf-8 -*-
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from django.utils.html import mark_safe
from django.db.models import Sum
from datetime import datetime
from model_utils import FieldTracker
from middleware import get_current_user


class InlineAwareModel(object):
    pass

class Zone(models.Model):
    name = models.CharField(u'Название', max_length=256)

    class Meta:
        verbose_name_plural = u'Зоны'
        verbose_name = u'Зона'

    def __unicode__(self):
        return self.name


class ServiceParameter(models.Model):
    name = models.CharField(max_length=255, verbose_name=u'Название')

    class Meta:
        verbose_name = u'Параметр подключения'
        verbose_name_plural = u'Параметры подключения'

    def __unicode__(self):
        return self.name


class ConnectionType(models.Model):
    title = models.CharField(u'Название', max_length=255)
    parameters = models.ManyToManyField(ServiceParameter, verbose_name=u'Параметры подключения')
    connect = models.TextField(u'Подключение')
    disconnect = models.TextField(u'Отключение')
    block = models.TextField(u'Блок')
    activate = models.TextField(u'Активация')


    class Meta:
        verbose_name = u'Тип подключения'
        verbose_name_plural = u'Типы подключения'

    def __unicode__(self):
        return self.title


class ServiceTemplate(models.Model):
    PERMANENT = 'P'
    TEMPORARY = 'T'
    TYPES = ((PERMANENT, u'Постоянная'), (TEMPORARY, u'Временная'))
    name = models.CharField(u'Название', max_length=256)
    type = models.CharField(u'Тип', choices=TYPES, max_length=1)


    class Meta:
        verbose_name = u'Шаблон услуги'
        verbose_name_plural = u'Шаблоны услуг'

    def __unicode__(self):
        return self.name


class Client(models.Model):
    INDIVIDUAL = u'I'
    LEGAL = u'L'
    ENTITY_TYPE = [(INDIVIDUAL, u'Физическое лицо'), (LEGAL, u'Юридическое лицо')]

    name = models.CharField(u'Наименование', max_length=256)
    type = models.CharField(u'Тип', max_length=1, choices=ENTITY_TYPE, blank=True)
    passeria = models.CharField(u'Серия паспорта', max_length=12, blank=True)
    pasnomer = models.CharField(u'Номер паспорта', max_length=12, blank=True)
    paspodrazdelenie = models.CharField(u'Код подразделения', max_length=12, blank=True)
    pasdate = models.DateField(u'Дата выдачи', null=True, blank=True)
    address = models.TextField(u'Адрес клиента', blank=True, null=True)
    phone = models.CharField(u'Телефон', max_length=32)
    email = models.EmailField(u'E-mail', blank=True)
    balance = models.DecimalField(max_digits=20, decimal_places=2)
    bonus_points = models.IntegerField()
    comments = models.TextField(u'Комментарий', blank=True)
    inn = models.CharField(u'ИНН', max_length='12', blank=True)

    def __unicode__(self):
        return self.name

    def balance(self):
        sum = self.operations.aggregate(amount=Sum("amount", default=0))["amount"]
        return sum if sum is not None else 0

    def monthly_cost(self):
        sum = self.services.aggregate(amount=Sum("price", default=0))["amount"]
        return sum if sum is not None else 0

    balance.short_description = u'Текущий баланс'

    def bonus_points(self):
        sum = self.bonuses.aggregate(amount=Sum("amount", default=0))["amount"]
        return sum if sum is not None else 0

    bonus_points.short_description = u'Бонусные баллы'

    class Meta:
        verbose_name = u'Клиент'
        verbose_name_plural = u'Клиенты'


class GtLinkUser(models.Model):
    user = models.OneToOneField(User, primary_key=True, blank=True)
    client = models.ForeignKey(Client, verbose_name=u'Клиент')

    class Meta:
        verbose_name = u'Пользователь'
        verbose_name_plural = u'Пользователи'


class Agreement(models.Model, InlineAwareModel):
    number = models.CharField(u'Номер', max_length=255, unique=True)
    client = models.ForeignKey(Client, verbose_name=u'Клиент', related_name='agreements')

    def monthly_cost(self):
        sum = self.services.aggregate(amount=Sum("price", default=0))["amount"]
        return sum if sum is not None else 0


    def __unicode__(self):
        return self.number

    def save(self, *args, **kwargs):
        super(Agreement, self).save(*args, **kwargs)
        for op in Operation.objects.filter(agreement_number=self.number, agreement__isnull=True):
            op.agreement = self
            op.client = self.client
            op.save()

        client = self.client
        if list(client.agreements.all()).index(self) == 0:
            client_users = GtLinkUser.objects.filter(client=client)
            if client_users.count() == 0:
                user = User.objects.create_user(self.number, client.email, client.phone[-4:])
                user.save()
                client_user =  GtLinkUser(client=client, user=user)
                client_user.save()

    def balance(self):
        sum = self.operations.aggregate(amount=Sum("amount", default=0))["amount"]
        return sum if sum is not None else 0

    def monthly_cost(self):
        sum = self.services.aggregate(amount=Sum("price", default=0))["amount"]
        return sum if sum is not None else 0

    class Meta:
        verbose_name = u'Договор'
        verbose_name_plural = u'Договоры'


class Service(models.Model, InlineAwareModel):
    STATUS_ACTIVE = u'ACTIVE'
    STATUS_MANUAL_BLOCK = u'M_BLCK'
    STATUS_FINANCIAL_BLOCK = u'F_BLCK'
    STATUS = [(STATUS_ACTIVE, u'Активна'),
              (STATUS_MANUAL_BLOCK, u'Ручная блокировка'),
              (STATUS_FINANCIAL_BLOCK, u'Финансовая блокировка')]
    template = models.ForeignKey(ServiceTemplate, verbose_name=u'Шаблон услуги')
    status = models.CharField(u'Статус', max_length=6, blank=False, null=False, choices=STATUS)
    zone = models.ForeignKey(Zone, verbose_name=u'Зона')
    address = models.TextField(u'Адрес', default='')
    client = models.ForeignKey(Client, related_name='services', verbose_name=u'Клиент')
    agreement = models.ForeignKey(Agreement, verbose_name=u'Договор', related_name='services')
    price = models.IntegerField(u'Стоимость')
    connection_type = models.ForeignKey(ConnectionType, verbose_name=u'Тип подключения', null=True)
    code_connect = models.TextField(u'Подключение')
    code_disconnect = models.TextField(u'Отключение')
    code_block = models.TextField(u'Блок')
    code_activate = models.TextField(u'Активация')

    tracker = FieldTracker()

    class Meta:
        verbose_name = u'Услуга'
        verbose_name_plural = u'Услуги'

    def __unicode__(self):
        return self.template.name

    def save(self, *args, **kwargs):
        changes = dict((key, value) for (key, value) in self.tracker.changed().iteritems() if value)
        exists = self.pk

        super(Service, self).save(*args, **kwargs)
        if not exists:
            changeset = ServiceChangeset(date=datetime.now(), author=get_current_user(), service=self, initial=True)
            changeset.save()
        elif len(changes):
            changeset = ServiceChangeset(date=datetime.now(), author=get_current_user(), service=self)
            changeset.save()

            for field, val in changes.iteritems():
                if val:
                    ref_field = field[:-3] if field.endswith("_id") else field
                    old = self._meta.get_field_by_name(ref_field)[0].related.parent_model.objects.get(
                        pk=val) if field.endswith("_id") else val
                    to = u"%s" % getattr(self, ref_field)
                    field_name = self._meta.get_field_by_name(ref_field)[0].verbose_name
                    if ref_field == 'status':
                        s = Service(status=old)
                        old = s.get_status_display()
                        to = self.get_status_display()

                    change = ServiceChange(field=field_name, value=to, old=old, changeset=changeset)
                    change.save()


class ServiceChangeset(models.Model):
    date = models.DateTimeField()
    author = models.ForeignKey(User)
    initial = models.BooleanField(default=0)
    service = models.ForeignKey(Service, related_name="changesets")


class ServiceChange(models.Model):
    field = models.CharField(max_length=255)
    value = models.CharField(max_length=255)
    old = models.CharField(max_length=255, null=True)
    changeset = models.ForeignKey(ServiceChangeset, related_name="changes")


class ServiceParameterValue(models.Model):
    parameter = models.ForeignKey(ServiceParameter, verbose_name=u'Параметр')
    value = models.CharField(max_length=255, verbose_name=u'Значение')
    service = models.ForeignKey(Service)

    class Meta:
        verbose_name = u'Параметр подключения'
        verbose_name_plural = u'Параметры подключения'


class Price(models.Model, InlineAwareModel):
    zone = models.ForeignKey(Zone, verbose_name=u'Зона')
    service = models.ForeignKey(ServiceTemplate, verbose_name=u'Шаблон услуги')
    amount = models.IntegerField(u'Стоимость')
    created = models.DateField(u'Дата создания', auto_now_add=True, blank=False)

    class Meta:
        verbose_name = u'Цена на услугу'
        verbose_name_plural = u'Цены на услуги'

    def __unicode__(self):
        return self.service.name


class Bonus(models.Model):
    amount = models.IntegerField(u'Количество')
    client = models.ForeignKey(Client, related_name='bonuses', verbose_name=u'Клиент', null=True)
    agreement = models.ForeignKey(Agreement, verbose_name=u'Договор', related_name='bonuses', null=True, blank=True)
    date = models.DateTimeField(u'Дата и время', default=datetime.now)
    author = models.ForeignKey(User, verbose_name=u'Автор', null=True)

    def __unicode__(self):
        return u'%s бонусов' % self.amount

    class Meta:
        verbose_name = u'Бонус'
        verbose_name_plural = u'Бонусы'


class Operation(models.Model):
    name = models.CharField(u'Описание', max_length=255)
    amount = models.DecimalField(u'Сумма', max_digits=19, decimal_places=2)
    client = models.ForeignKey(Client, related_name='operations', verbose_name=u'Клиент', null=True)
    agreement = models.ForeignKey(Agreement, verbose_name=u'Договор', related_name='operations', null=True, blank=True)
    agreement_number = models.CharField(u'Номер договора', max_length=20, null=True)
    date = models.DateTimeField(u'Дата и время', default=datetime.now)
    payment_id = models.IntegerField(u'Идентификатор платежа', null=True, blank=True)
    author = models.ForeignKey(User, verbose_name=u'Автор', null=True)

    def from_payment_system(self):
        return self.payment_id != "" and self.payment_id is not None

    from_payment_system.boolean = True
    from_payment_system.short_description = u'Из платежной системы'

    def __unicode__(self):
        return self.name

    class Meta:
        verbose_name = u'Операция со счетом'
        verbose_name_plural = u'Операции со счетом'


class InlineSettings(models.Model):
    name = models.CharField(u'Модель', max_length=255)

    class Meta:
        verbose_name = u'Настройки встроенного отображения'
        verbose_name_plural = u'Настройки встроенного отображения'

    def __unicode__(self):
        return u'Настройки отображения полей: %s' % self.name

    def settings(self):
        return mark_safe('<br/>'.join(self.field_settings.filter(visible=True).values_list('verbose', flat=True)))


class InlineSettingsField(models.Model):
    name = models.CharField(u'Поле', max_length=255)
    verbose = models.CharField(max_length=255, default='')
    visible = models.BooleanField(u'Отображать', default=True)
    model_settings = models.ForeignKey(InlineSettings, related_name='field_settings', null=False)

    class Meta:
        verbose_name = u'Настройка отображения поля'
        verbose_name_plural = u'Настройки отображения полей'

    def __unicode__(self):
        return u'Настройка отображения поля "%s" модели "%s"' % (self.name, self.model_settings.name)



